package com.xdwanj.smartcity.data.repository.impl;

import android.util.Log;

import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.StringRequest;
import com.xdwanj.smartcity.App;
import com.xdwanj.smartcity.data.bean.User;
import com.xdwanj.smartcity.data.bean.result.LoginResult;
import com.xdwanj.smartcity.data.bean.result.Result;
import com.xdwanj.smartcity.data.bean.result.UserResult;
import com.xdwanj.smartcity.data.config.Configs;
import com.xdwanj.smartcity.data.repository.IUserRepository;
import com.xdwanj.smartcity.util.Constants;
import com.xdwanj.smartcity.util.EncodedUtils;

import java.util.HashMap;
import java.util.Map;

public class UserRepository implements IUserRepository {
    private static final String TAG = "UserRepository";
    private static UserRepository INSTANCE = null;

    private UserRepository() {
    }

    public static UserRepository getInstance() {
        if (INSTANCE != null)
            return INSTANCE;
        else
            throw new IllegalStateException("not init");
    }

    public static void init() {
        INSTANCE = new UserRepository();
    }

    @Override
    public LiveData<Boolean> insertFeedBack(String title, String content) throws Exception {
        MutableLiveData<Boolean> data = new MutableLiveData<>();
        String url = Configs.BASE_URL + "/prod-api/api/common/feedback";

        StringRequest request = new StringRequest(Request.Method.POST, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    Result result = App.gson.fromJson(str, Result.class);
                    if (result.getCode().equals(200)) {
                        data.setValue(true);
                    } else {
                        data.setValue(false);
                    }
                },
                volleyError -> Log.d(TAG, "onErrorResponse: " + volleyError)
        ) {
            @Override
            public String getBodyContentType() {
                return Constants.APPLICATION_JSON;
            }

            @Override
            public byte[] getBody() throws AuthFailureError {
                HashMap<String, String> map = new HashMap<>();
                map.put("title", title);
                map.put("content", content);
                return EncodedUtils.localToRemote(App.gson.toJson(map)).getBytes(Configs.REMOTE_ENCODE);
            }
        };

        App.queue.add(
                request.setTag(TAG)
                        .setShouldCache(false)
        );

        return data;
    }

    @Override
    public LiveData<Boolean> updatePwd(String oldPwd, String newPwd) throws Exception {
        MutableLiveData<Boolean> data = new MutableLiveData<>();
        String url = Configs.BASE_URL + "/prod-api/api/common/user/resetPwd";

        StringRequest request = new StringRequest(Request.Method.PUT, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    Result result = App.gson.fromJson(str, Result.class);
                    if (result.getCode().equals(200)) {
                        data.setValue(true);
                    } else {
                        data.setValue(false);
                    }
                },
                volleyError -> Log.d(TAG, "onErrorResponse: " + volleyError)
        ) {
            @Override
            public byte[] getBody() throws AuthFailureError {
                HashMap<String, String> map = new HashMap<>();
                map.put("newPassword", newPwd);
                map.put("oldPassword", oldPwd);
                return EncodedUtils.localToRemote(App.gson.toJson(map)).getBytes(Configs.REMOTE_ENCODE);
            }

            @Override
            public String getBodyContentType() {
                return Constants.APPLICATION_JSON;
            }
        };
        request.setShouldCache(false);
        request.setTag(TAG);
        App.queue.add(request);
        return data;
    }

    @Override
    public void logout() throws Exception {
        String url = Configs.BASE_URL + "/logout";

        StringRequest request = new StringRequest(Request.Method.POST, url,
                s -> Log.d(TAG, "onResponse: " + s),
                volleyError -> Log.d(TAG, "onErrorResponse: " + volleyError)
        ) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> map = new HashMap<>();
                map.put(Constants.AUTHORIZATION, Configs.TOKEN);
                return map;
            }
        };

        App.sp.edit()
                .remove("token")
                .apply();

        Configs.TOKEN = null;

        App.queue.add(
                request.setShouldCache(false)
                        .setTag(TAG)
        );
    }

    @Override
    public LiveData<Boolean> updateUserInfo(User user) throws Exception {
        MutableLiveData<Boolean> data = new MutableLiveData<>();
        String url = Configs.BASE_URL + "/prod-api/api/common/user";

        StringRequest request = new StringRequest(Request.Method.PUT, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    Result result = App.gson.fromJson(str, Result.class);
                    if (result.getCode().equals(200)) {
                        data.setValue(true);
                    } else {
                        data.setValue(false);
                    }
                },
                volleyError -> Log.d(TAG, "onErrorResponse: " + volleyError)
        ) {
            @Override
            public String getBodyContentType() {
                return Constants.APPLICATION_JSON;
            }

            @Override
            public byte[] getBody() throws AuthFailureError {
                return EncodedUtils.localToRemote(App.gson.toJson(user)).getBytes(Configs.REMOTE_ENCODE);
            }
        };

        request.setTag(TAG);
        request.setShouldCache(false);
        App.queue.add(request);
        return data;
    }

    @Override
    public LiveData<Boolean> register(String username, String password, String phone, int sex) throws Exception {
        String url = Configs.BASE_URL + "/prod-api/api/register";
        MutableLiveData<Boolean> flag = new MutableLiveData<>();
        HashMap<String, String> map = new HashMap<>();
        map.put("username", username);
        map.put("password", password);
        map.put("phone", phone);
        map.put("sex", sex + "");
        String json = App.gson.toJson(map);

        StringRequest request = new StringRequest(Request.Method.POST, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    Result result = App.gson.fromJson(str, Result.class);
                    if (result.getCode().equals(200)) {
                        flag.setValue(true);
                    } else {
                        flag.setValue(false);
                    }
                    Log.d(TAG, "register: " + flag.getValue());
                },
                volleyError -> Log.d(TAG, "onErrorResponse: " + volleyError)
        ) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> hashMap = new HashMap<>();
                hashMap.put("Content-Type", Constants.APPLICATION_JSON);
                return hashMap;
            }

            @Override
            public String getBodyContentType() {
                return Constants.APPLICATION_JSON;
            }

            @Override
            public byte[] getBody() throws AuthFailureError {
                return EncodedUtils.localToRemote(json).getBytes(Configs.REMOTE_ENCODE);
            }
        };
        request.setShouldCache(false);
        App.queue.add(request);
        return flag;
    }

    @Override
    public LiveData<Boolean> isOnline(LifecycleOwner context) throws Exception {
        LiveData<User> userLiveData = getUser();
        MutableLiveData<Boolean> data = new MutableLiveData<>();

        userLiveData.observe(context, user -> {
            if (user != null) {
                data.setValue(true);
            } else {
                data.setValue(false);
            }
        });

        return data;
    }

    @Override
    public LiveData<String> login(String username, String password) throws Exception {
        String url = Configs.BASE_URL + "/prod-api/api/login";
        Map<String, String> map = new HashMap<>();
        map.put("username", username);
        map.put("password", password);
        String json = App.gson.toJson(map);
        MutableLiveData<String> liveData = new MutableLiveData<>();

        StringRequest request = new StringRequest(Request.Method.POST, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    String token = App.gson.fromJson(str, LoginResult.class).getToken();
                    try {
                        this.saveToken(token);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    liveData.setValue(token);
                },
                volleyError -> Log.d(TAG, "login: " + volleyError)
        ) {
            @Override
            public String getBodyContentType() {
                return Constants.APPLICATION_JSON;
            }

            @Override
            public byte[] getBody() throws AuthFailureError {
                return EncodedUtils.localToRemote(json).getBytes(Configs.REMOTE_ENCODE);
            }
        };
        request.setShouldCache(false);
        App.queue.add(request);
        return liveData;
    }

    @Override
    public boolean saveToken(String token) throws Exception {
        boolean flag = App.sp.edit()
                .putString(Constants.TOKEN, token)
                .commit();
        if (flag) {
            Configs.TOKEN = token;
        }
        return flag;
    }

    @Override
    public LiveData<User> getUser() throws Exception {
        MutableLiveData<User> data = new MutableLiveData<>();
        String url = Configs.BASE_URL + "/prod-api/api/common/user/getInfo";

        StringRequest request = new StringRequest(Request.Method.GET, url,
                s -> {
                    String str = EncodedUtils.remoteToLocal(s);
                    UserResult userResult = App.gson.fromJson(str, UserResult.class);
                    System.out.println("App.gson.toJson(userResult) = " + App.gson.toJson(userResult));
                    data.setValue(userResult.getUser());
                },
                volleyError -> volleyError.printStackTrace()
        ) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> map = new HashMap<>();
                map.put(Constants.AUTHORIZATION, Configs.TOKEN);
                return map;
            }
        };
        request.setShouldCache(false);
        request.setTag(TAG);
        App.queue.add(request);

        return data;
    }

    @Override
    public String getDiskToken() throws Exception {
        return App.sp.getString(Constants.TOKEN, null);
    }

    @Override
    public void cancelAll() throws Exception {
        App.queue.cancelAll(TAG);
    }
}
